﻿using FastMvc.Crud;
using FastMvc.Exceptions;
using FastMvc.Repositories;
using JQ.SAAS.DTO.SysOrganization;
using JQ.SAAS.Entity;
using JQ.SAAS.IService;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JQ.SAAS.Service
{
    public class SysOrgService : CrudService<sys_organization, SysOrgDto, string, SysOrgListRequestDto, SysOrgCreateUpdateDto, SysOrgCreateUpdateDto>, ISysOrgService
    {
        private IRepository<sys_org_menu> _orgMenuRepository;
        private IRepository<sys_menu> _menuRepository;
        private IRepository<org_role> _roleRepository;
        private IRepository<org_role_menu> _roleMenuRepository;
        private IRepository<org_user_role> _userRoleRepository;
        private IRepository<sys_user> _userRepository;
        private IRepository<sys_menu_set> _sysMenuSetRepository;
        private IRepository<org_menu_set> _orgMenuSetRepository;
        public SysOrgService(
            IRepository<sys_organization> repository,
            IRepository<sys_org_menu> orgMenuRepository,
            IRepository<sys_menu> menuRepository,
            IRepository<org_role> roleRepository,
            IRepository<org_role_menu> roleMenuRepository,
            IRepository<org_user_role> userRoleRepository,
            IRepository<sys_user> userRepository,
            IRepository<sys_menu_set> sysMenuSetRepository,
            IRepository<org_menu_set> orgMenuSetRepository)
            : base(repository)
        {
            _orgMenuRepository = orgMenuRepository;
            _menuRepository = menuRepository;
            _roleRepository = roleRepository;
            _roleMenuRepository = roleMenuRepository;
            _userRoleRepository = userRoleRepository;
            _userRepository = userRepository;
            _sysMenuSetRepository = sysMenuSetRepository;
            _orgMenuRepository = orgMenuRepository;
        }

        protected override ISugarQueryable<sys_organization> SetSugarQueryable(ISugarQueryable<sys_organization> query, SysOrgListRequestDto requestDto = null)
        {
            query = query.WhereIF(requestDto != null && !string.IsNullOrEmpty(requestDto.OrgName), t => t.sOrgName.Contains(requestDto.OrgName));

            return query;
        }

        public override async Task<SysOrgDto> CreateNew(SysOrgCreateUpdateDto createDto)
        {
            // 新建机构(机构建立完成后，默认建立管理员角色，以及管理员账号，并且为管理员角色添加机构当前的所有菜单，为管理员账户分配管理员角色)
            // TO_DO 1. 或者直接通过IsAdmin来处理呢？？管理员有且只能有一个！？
            // TO_DO 2. 涉及到多个Repository的时候，现在这种事务处理还是不行，需要再好一点的写法

            // 机构
            var orgDb = await MapToEntity(createDto);

            await Repository.InsertAsync(orgDb);

            // 获取可以默认分配的页面，包括管理员页面和一些基础页面
            List<sys_menu> defaultMenus = (await _menuRepository.GetAllAsync(t => t.iClassify == 1 || t.iClassify == 2)).ToList();

            // 机构的默认管理页面，默认Source页面
            List<sys_org_menu> DefaultOrgMenuList = new List<sys_org_menu>();
            foreach (var menu in defaultMenus)
            {
                var orgMenu = new sys_org_menu()
                {
                    sMenuId = menu.sId,
                    sMenuName = menu.sName,
                    sMenuPermission = menu.sPermission,
                    sMenuType = menu.iType,
                    sOrgId = orgDb.sId,
                    sOrgName = orgDb.sOrgName,
                    sParentMenuId = menu.ParentId
                };
                await _orgMenuRepository.InsertAsync(orgMenu);
                DefaultOrgMenuList.Add(orgMenu);
            }

            // 为机构建立默认逻辑页面
            var sysMenuSets = _sysMenuSetRepository.GetAll();
            List<org_menu_set> allOrgMenus = new List<org_menu_set>();
            foreach (var om in sysMenuSets)
            {
                var menuSet = new org_menu_set() 
                {
                    iSort =1,
                    sMenuId = om.sMenuId,
                    sMenuType = om.sMenuType,
                    sOrgId = orgDb.sId,
                    sOrgName = orgDb.sOrgName,
                    sShowName = om.sShowName,
                    SPermission = om.SPermission,
                    sShowIco = "",
                    sParentMenuId = om.sParentMenuId
                };
                allOrgMenus.Add(menuSet);
                await _orgMenuSetRepository.InsertAsync(menuSet);
            }

            // 机构的管理员角色
            var org_role = new org_role()
            {
                sName = "机构管理员",
                sOrgId = orgDb.sId,
                sOrgName = orgDb.sOrgName,
                iEnabled = 0
            };
            await _roleRepository.InsertAsync(org_role);

            // 为机构管理员分配默认逻辑页面
            foreach (var mSet in allOrgMenus)
            {
                var roleMenu = new org_role_menu() 
                {
                    slMenuId = mSet.sMenuId,
                    slMenuName = mSet.sShowName,
                    slMenuType = mSet.sMenuType,
                    sOrgId = orgDb.sId,
                    sOrgName = orgDb.sOrgName,
                    sRoleId = org_role.sId,
                    SPermission = mSet.SPermission,
                };
                await _roleMenuRepository.InsertAsync(roleMenu);
            }

            // 机构的管理员用户
            var org_Admin = new sys_user() 
            {
                LoginName = "admin_"+orgDb.sOrgCode,
                Password = "qwe123",
                iEnabled =0,
                iLocked =0,
                NickName = orgDb.sOrgName+"管理员",
                sOrgId = orgDb.sId,
                sOrgName = orgDb.sOrgName
            };
            await _userRepository.InsertAsync(org_Admin);

            // 为管理员用户分配管理员角色
            org_user_role user_Role = new org_user_role() 
            {
                sOrgId = orgDb.sId,
                sOrgName = orgDb.sOrgName,
                sRoleId = org_role.sId,
                sRoleName = org_role.sName,
                sUserId = org_Admin.sId,
                sUserNickName = org_Admin.NickName
            };
            await _userRoleRepository.InsertAsync(user_Role);

            return await MapToDto(orgDb);
        }

        public async Task<List<SysOrgMenuListDto>> GetOrgMenuList(string sOrgId)
        {
            var db = this.SugarClient;
            return await db.Queryable<sys_organization, sys_org_menu, sys_menu>((o, om, m) => new object[]
                {
                    JoinType.Left, o.sId == om.sOrgId,
                    JoinType.Left, om.sMenuId == m.sId
                })
                .Where((o, om, m) => m.iType == 0) // 只获取页面代码
                .Where((o, om, m) => o.sId == sOrgId)
                .Select((o, om, m) => new SysOrgMenuListDto()
                {
                    sMenuId = m.sId,
                    MenuName = m.sName
                })
                .ToListAsync();
        }

        public async Task SetOrgMenus(string sOrgId, List<SysOrgMenuListDto> sMenus)
        {
            var org = await Repository.FirstOrDefaultAsync(t => t.sId == sOrgId);
            if (org == null)
                throw new ApiException("未找到对应的机构！");


            var sMenuIds = sMenus.Select(t => t.sMenuId).ToList();

            // 这里传过来的只是页面菜单的代码，要补上各自对应的操作菜单
            var AllMenus = await _menuRepository.GetAllAsync(m => m.iType == 0 && sMenuIds.Contains(m.sId) || (m.iType == 1 && sMenuIds.Contains(m.ParentId)));

            sMenuIds = AllMenus.Select(t => t.sId).ToList();

            // 查询机构当前已经配置的
            var curList = (await _orgMenuRepository.GetAllAsync()).Select(t => t.sMenuId);

            // 删除不存在的
            var delList = curList.Where(t => !sMenuIds.Contains(t));
            await _orgMenuRepository.DeleteAsync(t => delList.Contains(t.sId));

            // 增加新增的
            var addList = AllMenus.Where(t => !curList.Contains(t.sId));

            foreach (var ad in addList)
            {
                sys_org_menu om = new sys_org_menu() 
                {
                    sId = Guid.NewGuid().ToString(),
                    sOrgId = sOrgId,
                    sOrgName = org.sOrgName,
                    sMenuName = ad.sName,
                    sMenuId = ad.sId,
                    sMenuPermission = ad.sPermission,
                    sMenuType = ad.iType,
                    // dExpireTime = 
                };
                await _orgMenuRepository.InsertAsync(om);
            }
        }
    }
}
